/*
 * Stack.h
 *
 *  Created on: Oct 15, 2010
 *      Author: Jacob
 */

#pragma once
#include "stdafx.h"
#include "Node.h"
#include <sstream>
using std::string;
using std::ostringstream;
using std::stringstream;

template<typename T>
class Stack
{
public:
	static Stack<T>* newStack();
	void push(Node<T>* nodeToBeAdded);
	void push(T data);
	Node<T>* pop();
	Node<T>* getTop();
	int getSize();
	bool isEmpty();
	void clear();
	void setName(string name);
	string toString();
	virtual ~Stack();
private:
	string name;
	Node<T>* top;
	int size;
	Node<T>* constructNodeFromT(T data);
	bool containsData();
	void pushNodeOnStack(Node<T>* nodeToBePushed);
	void deleteNode(Node<T>* nodeToBeDeleted);
	void modifySize(int amount);
	Stack();
};

template<typename T>
Stack<T>* Stack<T>::newStack()
{
	return new Stack<T> ();
}

template<typename T>
Stack<T>::Stack()
{
	this->name = "-----";
	//top = NULL;
	size = 0;
}

template<typename T>
Stack<T>::~Stack()
{
	cout << " | Stack Destructor Called";
	delete this->top;
}

template<typename T>
void Stack<T>::push(T data)
{
	Node<T>* newNode = constructNodeFromT(data);
	pushNodeOnStack(newNode);
}

template<typename T>
void Stack<T>::push(Node<T>* nodeToBeAdded)
{
	pushNodeOnStack(nodeToBeAdded);
}

template<typename T>
Node<T>* Stack<T>::constructNodeFromT(T data)
{
	Node<T>* temporaryNode = Node<T>::newNodeFromData(data);
	return temporaryNode;
}

template<typename T>
void Stack<T>::pushNodeOnStack(Node<T>* nodeToBePushed)
{
	if (isEmpty() == false)
	{
		nodeToBePushed->setNext(top);
		top = nodeToBePushed;
	}
	else
		top = nodeToBePushed;

	modifySize(1);
}

template<typename T>
Node<T>* Stack<T>::pop()
{
	if (isEmpty() == false)
	{
		Node<T>* temporaryNode = top;
		top = top->getNext();
		temporaryNode->setNext(NULL);
		modifySize(-1);
		return temporaryNode;
	}

	return NULL;
}

template<typename T>
Node<T>* Stack<T>::getTop()
{
	return top;
}

template<typename T>
void Stack<T>::clear()
{
	int sizeBeforeClear = size;
	for (int index = 0; index < sizeBeforeClear; index++)
	{
		Node<T>* top = this->pop();
		delete top;
	}
}

template<typename T>
void Stack<T>::setName(string name)
{
	this->name = name;
}

template<typename T>
string Stack<T>::toString()
{
	ostringstream stringStream;

	Node<T>* current = top;
	stringStream << "\n--------------" << name << "----------------";
	for (int index = 0; index < size; index++)
	{
		stringStream << "\n" << current->toString(); //<< "     PTR: " << current;
		current = current->getNext();
	}

	stringStream << "\n-----------------------------------";//\nSize: " << size << "\n-----------------------------------";

	return stringStream.str();
}


template<typename T>
int Stack<T>::getSize()
{
	return this->size;
}

template<typename T>
bool Stack<T>::isEmpty()
{
	if (size > 0)
		return false;
	else
		return true;
}

template<typename T>
void Stack<T>::modifySize(int amount)
{
	size += amount;
}


